﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

using MediatR;

using SW.DDD.Infrastructure;

namespace SW.DDD.Domain.EventDispatcher
{
    public class MediatRUnitOfWork : IUnitOfWork
    {
        private readonly IUnitOfWork _backingUnitOfWork;
        private readonly IMediator _mediator;

        public MediatRUnitOfWork(IUnitOfWork backingUnitOfWork, IMediator mediator)
        {
            _backingUnitOfWork = backingUnitOfWork;
            _mediator = mediator;
        }

        public async Task<IEnumerable<IEntity>> SaveChangesAsync(CancellationToken cancellationToken = default)
        {
            var entities = (await _backingUnitOfWork.SaveChangesAsync(cancellationToken)).ToArray();
            foreach (var @event in entities.SelectMany(e => e.DequeenAllEvent()).ToArray())
            {
                await _mediator.Publish(@event, cancellationToken);
            }

            return entities;
        }

        public Task BeginTransactionAsync(CancellationToken cancellationToken = default) => 
            _backingUnitOfWork.BeginTransactionAsync(cancellationToken);

        public Task CommitTransactionAsync(CancellationToken cancellationToken = default) => 
            _backingUnitOfWork.CommitTransactionAsync(cancellationToken);

        public Task RollbackTransactionAsync(CancellationToken cancellationToken = default) => 
            _backingUnitOfWork.RollbackTransactionAsync(cancellationToken);

        public Guid? GetCurrentTransactionId() => 
            _backingUnitOfWork.GetCurrentTransactionId();
    }
}
